import { CanActivate, ExecutionContext, Injectable, UnauthorizedException } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { JwtService } from '@nestjs/jwt';
import { Request } from 'express';
import { Role_KEY } from '../decorators/visitCheck';


@Injectable()
export class AuthGuard implements CanActivate {
  private readonly whitelist: string[] = ['/', '/error', '/auth/login', '/auth/register', '/auth/logout']
  constructor(
    private readonly reflector: Reflector,
    private readonly jwtService: JwtService
  ) { }
  async canActivate(context: ExecutionContext): Promise<boolean> {
    // 获取请求报文
    const request: Request = context.switchToHttp().getRequest<Request>();
    // 获取地址
    const url: string = request.url;
    // 获取函数体, 'role'表示seMetaData的第一个参数, 如果roleinfo不存在説明這個接口訪問沒有限制
    const roleInfo = this.reflector.get<string[] | undefined>(Role_KEY, context.getHandler());
    // 获取请求头的token
    const token: string | undefined = this.extractTokenFromHeader(request.get('Authorization'));
    // 白名单
    if (this.checkIsInWhite(url)) {
      // 重复登录
      if (this.checkIsRepeatLogin(url, token)) throw new UnauthorizedException('该账号已登录!');
      return true;
    }
    if (roleInfo == undefined || roleInfo.length === 0) return true;
    console.log(roleInfo);
    // 没有token
    if (token === undefined) throw new UnauthorizedException("unauthorized");


    try {
      const payload = await this.jwtService.verifyAsync(token);
      // console.log(payload)
    } catch (e) {
      throw new UnauthorizedException('登录已过期!');
    }

    return true
  }

  private checkIsInWhite(url: string) {
    url = url.indexOf('?') !== -1 ? url.slice(0, url.indexOf('?')) : url;
    return this.whitelist.includes(url);
  }

  private checkIsRepeatLogin(url: string, token: string | undefined) {
    return url.indexOf('/login') == -1 && !!token
  }

  private extractTokenFromHeader(url: string | string): string | undefined {
    const [type, token] = url?.split(' ') ?? [];
    return type === 'Bearer' ? token : undefined;
  }

}
